﻿/*
 * File: Contracts.cs
 * Developer : Brent Larsen (brentoboy@gmail.com)
 * Date: 2011-AUG-9
 * Copyright (c) 2011 Brent Larsen.
 * Distributed under the terms of the GPL v3
 *  
 * This file is part of GenX-RPG
 * http://code.google.com/p/genx-rpg/ 
 * 
 * GenX-RPG is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GenX-RPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with GenX-RPG.  If not, see <http://www.gnu.org/licenses/>.
 */


using System;
using System.Diagnostics;

namespace Rpg
{
    public class FeedbackException : ApplicationException
    {
        public FeedbackException(string message) : base(message) { }
    }

    public class UnexpectedCaseException : ApplicationException
    {
        public UnexpectedCaseException() : base() { }
        public UnexpectedCaseException(string message) : base(message) { }
    }

    public class CodeContractException : ApplicationException
    {
        public CodeContractException() : base() { }
        public CodeContractException(string message) : base(message) { }
    }

    public class RequirementException : CodeContractException
    {
        public RequirementException() : base() { }
        public RequirementException(string message) : base(message) { }
    }

    public class AssumptionException : CodeContractException
    {
        public AssumptionException() : base() { }
        public AssumptionException(string message) : base(message) { }
    }

    public class AssertionException : CodeContractException
    {
        public AssertionException() : base() { }
        public AssertionException(string message) : base(message) { }
    }

    public class PromiseException : CodeContractException
    {
        public PromiseException() : base() { }
        public PromiseException(string message) : base(message) { }
    }

    public class NotOverriddenException : NotImplementedException
    {
        public NotOverriddenException() : base() { }
    }

    /// <summary>
    /// Contracts are an excelent way of documenting what your code does and needs
    /// in a way that the documentation inforces itself. (through exceptions)
    /// </summary>
    public static class Contract
    {
        /// <summary>
        /// Requirements are tested at the top of a function before anything else
        /// is done.  The function is expected to test everything necessary in order
        /// to deliver on all of its promises.  The idea is that, so long as the 
        /// requirements are all met, then the promises will be delivered.
        /// </summary>
        public static void Requires(bool condition)
        {
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new RequirementException();
#endif
        }
        public static void Requires(Func<bool> test)
        {
            bool condition = test();
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new RequirementException();
#endif
        }

        /// <summary>
        /// Requirements are tested at the top of a function before anything else
        /// is done.  The function is expected to test everything necessary in order
        /// to deliver on all of its promises.  The idea is that, so long as the 
        /// requirements are all met, then the promises will be delivered.
        /// </summary>
        public static void Ensures(bool condition)
        {
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new PromiseException();
#endif
        }
        public static void Ensures(Func<bool> test)
        {
            bool condition = test();
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new PromiseException();
#endif
        }

        /// <summary>
        /// Assumptions should be added to code when you do not want to handle a
        /// particular scenario, becuase you dont expect it to ever be a problem
        /// but you want to protect yourself in the event that it does happen.
        /// 
        /// Assumptions are a way of procrastinating writing code to handle details
        /// that will probably change anyway as the code matures, so why invest in
        /// the fix today.
        /// </summary>
        public static void Assumes(bool condition)
        {
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new AssumptionException();
#endif
        }
        public static void Assumes(Func<bool> test)
        {
            bool condition = test();
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new AssumptionException();
#endif
        }

        /// <summary>
        /// An "assertion" implies that there was a problem in the process somewhere
        /// and that things should NOT continue because the foundation is no longer 
        /// dependable.
        /// 
        /// It is similar to both a "requirement" and a "promise" it is a test made
        /// inside of the process rather than at beginning or the end.  It can be
        /// thought of as a promise from the part of the process leading to that point
        /// and a requirment of the rest of the process.
        /// </summary>
        public static void Asserts(bool condition)
        {
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new AssertionException();
#endif
        }
        public static void Asserts(Func<bool> test)
        {
            bool condition = test();
#if DEBUG
            Debug.Assert(condition);
#else
            if (!condition) throw new AssertionException();
#endif
        }

        public static void UnexpectedCase(string caseDescription = null)
        {
#if DEBUG
            Debug.Assert(false);
#else
            throw new UnexpectedCaseException(caseDescription);
#endif
        }
    }
}